package cn.jinjimi.app;

import android.annotation.SuppressLint;
import android.os.Build;

import cn.jinjimi.domain.Executor;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import bolts.Task;

/**
 * Created by zhenhua on 16/7/8.
 *
 * A class from Bolt
 *
 * @see {@link "https://github.com/BoltsFramework/Bolts-Android"}
 */
public final class DefaultExecutor implements Executor {

    private static volatile DefaultExecutor mInstance = null;
    private final ExecutorService mExecutor;

    public static Executor get(){
        if(mInstance == null){
            synchronized (DefaultExecutor.class){
                if(mInstance == null){
                    mInstance = new DefaultExecutor();
                }
            }
        }
        return mInstance;
    }

    private DefaultExecutor(){
        mExecutor = newCachedThreadPool();
    }

    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
    private static final int MAX_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final long KEEP_ALIVE_TIME = 1L;

    private ExecutorService newCachedThreadPool(){
        ThreadPoolExecutor executor =  new ThreadPoolExecutor(
                CORE_POOL_SIZE,
                MAX_POOL_SIZE,
                KEEP_ALIVE_TIME, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>());

        allowCoreThreadTimeout(executor, true);

        return executor;
    }

    @SuppressLint("NewApi")
    public static void allowCoreThreadTimeout(ThreadPoolExecutor executor, boolean value) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
            executor.allowCoreThreadTimeOut(value);
        }
    }

    @Override
    public void execute(final Runnable operation){

        Task.call(new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                operation.run();
                return null;
            }
        }, mExecutor);

    }
}
